﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Police
{
    using Police.Helpers;
    /// <summary>
    /// Default pre-commit validation rules provider. Use this class helper's method
    /// to retrieve active and valid validations rules.
    /// </summary>
    public class PreCommitRulesProvider : IPreCommitRulesProvider
    {
        /// <summary>
        /// Prototype for rule entry.
        /// </summary>
        private class Entry
        {
            /// <summary>
            /// Gets or sets rule.
            /// </summary>
            public IPreCommitRule Rule { get; set; }

            /// <summary>
            /// Gets or sets rule's attributes.
            /// </summary>
            public PreCommitRuleAttribute Attribute { get; set; }
        }

        /// <summary>
        /// Load validation rules using reflection. Scann executing assembly and
        /// retrieve list of types that implement interface IPreCommitValidationRule.
        /// </summary>
        /// <returns>Returns list of valid and active validation rules.</returns>
        public IEnumerable<IPreCommitRule> LoadValidationRules()
        {
            Assembly assembly = Assembly.GetExecutingAssembly();
            List<Type> types = assembly.Find<IPreCommitRule>();
            List<Entry> entries = new List<Entry>();
            foreach (Type type in types)
            {
                Object attribute = type.GetCustomAttributes(typeof(PreCommitRuleAttribute), false).FirstOrDefault();
                if (attribute != null)
                {
                    entries.Add(new Entry
                    {
                        Rule = (IPreCommitRule)Activator.CreateInstance(type),
                        Attribute = (PreCommitRuleAttribute)attribute
                    });
                }
                else
                {

                    throw new InvalidOperationException(String.Format("Unable to initialize validation rules, for {0} attribute PreCommitRuleAttribute was not specified.", type.FullName));
                }
            }
            return entries
                .Where(e => e.Attribute.Enabled)
                .OrderBy(e => e.Attribute.Order)
                .Select(e => e.Rule);
        }
    }
}
